package com.sas.service.impl;

import com.sas.entity.Employee;
import com.sas.entity.SalaryInfo;
import com.sas.entity.Schedule;
import com.sas.repository.EmployeeRepository;
import com.sas.repository.SalaryInfoRepository;
import com.sas.repository.ScheduleRepository;
import com.sas.service.SalaryService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;

@Service
@Transactional
public class SalaryServiceImpl implements SalaryService {

    private static final Logger log = LoggerFactory.getLogger(SalaryServiceImpl.class);

    @Autowired
    private SalaryInfoRepository salaryInfoRepository;

    @Autowired
    private EmployeeRepository employeeRepository;

    @Autowired
    private ScheduleRepository scheduleRepository;

    @Override
    public SalaryInfo save(SalaryInfo salaryInfo) {
        salaryInfo.setUpdateTime(LocalDateTime.now());
        return salaryInfoRepository.save(salaryInfo);
    }

    @Override
    public Optional<SalaryInfo> findById(Long id) {
        return salaryInfoRepository.findById(id);
    }

    @Override
    public List<SalaryInfo> findAll() {
        return salaryInfoRepository.findAll();
    }

    @Override
    public Optional<SalaryInfo> findEffectiveSalaryInfo(Integer salaryLevel, Integer employeeType) {
        return salaryInfoRepository.findEffectiveSalaryInfo(salaryLevel, employeeType, LocalDateTime.now());
    }

    @Override
    public List<SalaryInfo> findByEmployeeType(Integer employeeType) {
        // 返回所有该类型的薪资配置（不限制生效区间）
        return salaryInfoRepository.findByEmployeeType(employeeType);
    }

    @Override
    public List<SalaryInfo> findAllEffective() {
        return salaryInfoRepository.findAllEffective(LocalDateTime.now());
    }

    @Override
    public SalaryInfo update(SalaryInfo salaryInfo) {
        salaryInfo.setUpdateTime(LocalDateTime.now());
        return salaryInfoRepository.save(salaryInfo);
    }

    @Override
    public void deleteById(Long id) {
        salaryInfoRepository.deleteById(id);
    }

    @Override
    public BigDecimal calculateSalary(Long employeeId, Double workHours,
                                      Boolean isNightShift, Boolean isWeekend,
                                      Boolean isHoliday, Double overtimeHours) {
        if (employeeId == null || workHours == null) {
            return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
        }

        Employee employee = employeeRepository.findById(employeeId).orElse(null);
        if (employee == null) {
            return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
        }

        // 查找生效的薪资配置，若不存在则使用简单的默认规则
        Optional<SalaryInfo> optInfo = salaryInfoRepository.findEffectiveSalaryInfo(
                employee.getSalaryLevel(), employee.getEmployeeType(), LocalDateTime.now());

        BigDecimal baseHourlyRate;
        BigDecimal overtimeRate = new BigDecimal("1.50");
        BigDecimal nightAllowance = BigDecimal.ZERO;
        BigDecimal weekendAllowance = BigDecimal.ZERO;
        BigDecimal holidayAllowance = BigDecimal.ZERO;

        if (optInfo.isPresent()) {
            SalaryInfo info = optInfo.get();
            baseHourlyRate = safe(info.getBaseHourlyRate(), new BigDecimal("20.00"));
            overtimeRate = safe(info.getOvertimeRate(), overtimeRate);
            nightAllowance = safe(info.getNightShiftAllowance(), BigDecimal.ZERO);
            weekendAllowance = safe(info.getWeekendAllowance(), BigDecimal.ZERO);
            holidayAllowance = safe(info.getHolidayAllowance(), BigDecimal.ZERO);
        } else {
            // 默认基础时薪：复用 ScheduleServiceImpl 的思路
            double baseRate = 20.0;
            Integer type = employee.getEmployeeType();
            if (type != null) {
                switch (type) {
                    case 1: baseRate *= 1.5; break; // 全职
                    case 2: baseRate *= 1.2; break; // 兼职
                    case 3: baseRate *= 1.0; break; // 临时工
                    default: break;
                }
            }
            if (employee.getSalaryLevel() != null) {
                baseRate *= (1.0 + employee.getSalaryLevel() * 0.1);
            }
            baseHourlyRate = BigDecimal.valueOf(baseRate);
        }

        BigDecimal workH = BigDecimal.valueOf(Math.max(0.0, workHours));
        BigDecimal otH = BigDecimal.valueOf(Math.max(0.0, overtimeHours == null ? 0.0 : overtimeHours));
        BigDecimal regularH = workH.subtract(otH).max(BigDecimal.ZERO);

        // 正常工资 + 加班工资
        BigDecimal regularPay = regularH.multiply(baseHourlyRate);
        BigDecimal overtimePay = otH.multiply(baseHourlyRate).multiply(overtimeRate);

        // 补贴（假设为按小时叠加的补贴）
        BigDecimal allowancePerHour = BigDecimal.ZERO;
        if (Boolean.TRUE.equals(isNightShift)) allowancePerHour = allowancePerHour.add(nightAllowance);
        if (Boolean.TRUE.equals(isWeekend)) allowancePerHour = allowancePerHour.add(weekendAllowance);
        if (Boolean.TRUE.equals(isHoliday)) allowancePerHour = allowancePerHour.add(holidayAllowance);
        BigDecimal allowancePay = workH.multiply(allowancePerHour);

        return regularPay.add(overtimePay).add(allowancePay).setScale(2, RoundingMode.HALF_UP);
    }

    @Override
    public BigDecimal calculateTotalSalary(Long employeeId, String startDate, String endDate) {
        if (employeeId == null || startDate == null || endDate == null) {
            return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
        }
        LocalDate start = LocalDate.parse(startDate);
        LocalDate end = LocalDate.parse(endDate);
        List<Schedule> schedules = scheduleRepository.findByEmployeeIdAndDateRange(employeeId, start, end);

        BigDecimal total = BigDecimal.ZERO;
        for (Schedule s : schedules) {
            double hours = Math.max(0, (double) java.time.Duration.between(s.getStartTime(), s.getEndTime()).toHours());
            double overtime = Math.max(0, hours - 8.0); // 简化：每日超过 8 小时记为加班
            boolean isWeekend = isWeekendDay(s.getScheduleDate());
            boolean isHoliday = false; // 如需节假日识别，可接入节假日服务
            boolean isNightShift = isNightShift(s.getStartTime(), s.getEndTime());
            total = total.add(calculateSalary(employeeId, hours, isNightShift, isWeekend, isHoliday, overtime));
        }
        return total.setScale(2, RoundingMode.HALF_UP);
    }

    @Override
    public BigDecimal calculateRoomSalaryCost(Long roomId, String startDate, String endDate) {
        if (roomId == null || startDate == null || endDate == null) {
            return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
        }
        LocalDate start = LocalDate.parse(startDate);
        LocalDate end = LocalDate.parse(endDate);
        List<Schedule> schedules = scheduleRepository.findByRoomIdAndDateRange(roomId, start, end);

        BigDecimal total = BigDecimal.ZERO;
        for (Schedule s : schedules) {
            Long empId = s.getEmployeeId();
            if (empId == null) continue;
            double hours = Math.max(0, (double) java.time.Duration.between(s.getStartTime(), s.getEndTime()).toHours());
            double overtime = Math.max(0, hours - 8.0);
            boolean isWeekend = isWeekendDay(s.getScheduleDate());
            boolean isHoliday = false;
            boolean isNightShift = isNightShift(s.getStartTime(), s.getEndTime());
            total = total.add(calculateSalary(empId, hours, isNightShift, isWeekend, isHoliday, overtime));
        }
        return total.setScale(2, RoundingMode.HALF_UP);
    }

    @Override
    public Object getSalaryComparison(String startDate, String endDate, String compareStartDate, String compareEndDate) {
        LocalDate s1 = LocalDate.parse(startDate);
        LocalDate e1 = LocalDate.parse(endDate);
        LocalDate s2 = LocalDate.parse(compareStartDate);
        LocalDate e2 = LocalDate.parse(compareEndDate);

        BigDecimal currentTotal = sumAllSchedulesSalary(s1, e1);
        BigDecimal compareTotal = sumAllSchedulesSalary(s2, e2);
        BigDecimal diff = currentTotal.subtract(compareTotal);
        BigDecimal percent = compareTotal.compareTo(BigDecimal.ZERO) == 0
                ? BigDecimal.ZERO
                : diff.divide(compareTotal, 4, RoundingMode.HALF_UP).multiply(new BigDecimal("100"));

        Map<String, Object> result = new HashMap<>();
        result.put("currentTotal", currentTotal);
        result.put("compareTotal", compareTotal);
        result.put("difference", diff);
        result.put("percentChange", percent.setScale(2, RoundingMode.HALF_UP));
        return result;
    }

    private BigDecimal sumAllSchedulesSalary(LocalDate start, LocalDate end) {
        List<Schedule> schedules = scheduleRepository.findByDateRange(start, end);
        BigDecimal total = BigDecimal.ZERO;
        for (Schedule s : schedules) {
            Long empId = s.getEmployeeId();
            if (empId == null) continue;
            double hours = Math.max(0, (double) java.time.Duration.between(s.getStartTime(), s.getEndTime()).toHours());
            double overtime = Math.max(0, hours - 8.0);
            boolean isWeekend = isWeekendDay(s.getScheduleDate());
            boolean isHoliday = false;
            boolean isNightShift = isNightShift(s.getStartTime(), s.getEndTime());
            total = total.add(calculateSalary(empId, hours, isNightShift, isWeekend, isHoliday, overtime));
        }
        return total.setScale(2, RoundingMode.HALF_UP);
    }

    private boolean isWeekendDay(LocalDate date) {
        if (date == null) return false;
        switch (date.getDayOfWeek()) {
            case SATURDAY:
            case SUNDAY:
                return true;
            default:
                return false;
        }
    }

    private boolean isNightShift(LocalTime start, LocalTime end) {
        if (start == null || end == null) return false;
        // 简化判断：开始在 22:00 之后或结束在 06:00 之前视为夜班
        return start.isAfter(LocalTime.of(22, 0)) || end.isBefore(LocalTime.of(6, 0));
    }

    private BigDecimal safe(BigDecimal val, BigDecimal def) {
        return val == null ? def : val;
    }
}